package cfca.paperless.client.servlet._2_extend._2_01_AutoCalculatePdfHash;

import java.io.File;
import java.security.PrivateKey;
import java.util.Date;

import org.apache.commons.io.FileUtils;

import cfca.paperless.client.bean.SignLocation;
import cfca.paperless.client.servlet.PaperlessClient;
import cfca.paperless.client.servlet.PaperlessConfig;
import cfca.paperless.client.util.GUID;
import cfca.paperless.client.util.IoUtil;
import cfca.paperless.client.util.PaperlessUtil;
import cfca.paperless.client.util.StrategyUtil;
import cfca.paperless.client.util.StringUtil;
import cfca.sadk.algorithm.common.Mechanism;
import cfca.sadk.asn1.pkcs.PKCS12;
import cfca.sadk.lib.crypto.JCrypto;
import cfca.sadk.lib.crypto.Session;
import cfca.sadk.util.Base64;
import cfca.sadk.util.P10Request;
import cfca.sadk.util.Signature;
import cfca.sadk.x509.certificate.X509Cert;

public class AutoCalculatePdfHashTest02 {

    /**
     * 调用自动化计算PDF签章HASH值接口
     * 使用临时申请的证书签名
     * 
     * @param args
     * @throws IOException
     * @throws
     */
    public static void main(String[] args) throws Exception {
        try {
            long timeStart = System.currentTimeMillis();// 开始时间

            // 初始化客户端对象
            PaperlessClient clientBean = new PaperlessClient(PaperlessConfig.extUrl, 10000, 60000);// 无纸化辅助接口的访问URL

            // 申请证书
            testApplyAndDownloadCert();

            // 待计算hash的pdf
            String filePath = "./TestData/autoCalculatePdfHash.pdf";
           
            String pdfSuffix = IoUtil.getFileNameSuffix(filePath);
            if(!PaperlessConfig.PDF_FILE_SUFFIX.equals(pdfSuffix)){
                throw new Exception("所选文件不是pdf文件");
            }
            
            byte[] pdf = FileUtils.readFileToByteArray(new File(filePath));
            
            String sealImagePath = "./TestData/zhangfei.png";
            String pngSuffix = IoUtil.getFileNameSuffix(sealImagePath);
            if(!PaperlessConfig.PNG_FILE_SUFFIX.equals(pngSuffix)){
                throw new Exception("所选文件不是png文件,签章图片文件只支持png格式图片");
            }
            // 印模图片
            byte[] sealImage = FileUtils.readFileToByteArray(new File(sealImagePath));
            // 签章位置
            SignLocation signLocation = new SignLocation("代理人签名", "R", 10, 10);
            // 策略文件
            String strategyXml = StrategyUtil.createClientSealStrategyXml("业务", "china", sealImage, signLocation, "SHA256", "");
            // 操作员编码或者机构号
            String operatorCode = PaperlessConfig.operatorCode;
            // 渠道编码，可以为空
            String channelCode = PaperlessConfig.channelCode;

            String systemNo = GUID.generateId();//业务流水号
            // 计算hash x509Cert参数可以为空，为空时外部合成签名只能是pkcs7
            String returnMessage = clientBean.autoCalculatePdfHash(systemNo,pdf, cert.getEncoded(), strategyXml, operatorCode, channelCode);

            String code = StringUtil.getNodeText(returnMessage, "Code");
            if ("200".equals(code)) {
                System.out.println("OK:autoCalculatePdfHash");
                String pdfSealHash = StringUtil.getNodeText(returnMessage, "PdfSealHash");
                String pdfSealSource = StringUtil.getNodeText(returnMessage, "PdfSealSource");
                String id = StringUtil.getNodeText(returnMessage, "Id");
                System.out.println("返回的PDF文档HASH值：" + pdfSealHash);
                System.out.println("返回的PDF文档原文：" + pdfSealSource);
                System.out.println("返回的ID：" + id);

                JCrypto.getInstance().initialize(JCrypto.JSOFT_LIB, null);
                cfca.sadk.lib.crypto.Session mySession = JCrypto.getInstance().openSession(JCrypto.JSOFT_LIB);
                Signature sigUtil = new Signature();
                // 对hash进行签名
                byte[] signature = sigUtil.p1SignByHash(Mechanism.SHA256_RSA,Base64.decode(pdfSealHash),privateKey, mySession);
//                signature = sigUtil.p7SignByHash(Mechanism.SHA1_RSA, Base64.decode(pdfSealHash), privateKey, cert, mySession);

                // 合成外部签名
                byte[] sealedPdfData = clientBean.synthesizeOuterSignature(systemNo,Base64.decode(signature), id, operatorCode, channelCode);
                String errorRsString = PaperlessUtil.isError(sealedPdfData);

                if ("".equals(errorRsString)) {
                    System.out.println("OK:synthesizeOuterSignature");
                    System.out.println(sealedPdfData.length);
                    IoUtil.write("./TestData/output/sealedPdf-" + new File(filePath).getName() + ".pdf", sealedPdfData);
                } else {
                    // 处理结果为异常，打印出错误码和错误信息
                    System.out.println("NG:synthesizeOuterSignature");
                    System.out.println(sealedPdfData.length);
                    System.out.println(new String(sealedPdfData, "UTF-8"));
                }
                long timeEnd = System.currentTimeMillis();// 结束时间
                System.out.println("time:" + (timeEnd - timeStart));
            } else {
                System.out.println("获得PDF文档HASH值失败！" + returnMessage);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    static PaperlessClient clientBean = new PaperlessClient(PaperlessConfig.assistUrl, 10000, 60000);

    static PrivateKey privateKey = null;
    static String p10String = null;
    static X509Cert cert = null;

    public static void testApplyAndDownloadCert() throws Exception {
        try {

            createP10();
            String result = clientBean.applyAndDownloadCert(getApplyCertStrategyXML(), PaperlessConfig.operatorCode, PaperlessConfig.channelCode);
            String code = StringUtil.getNodeText(result, "Code");
            // 返回值Code等于200代表后台处理成功
            if (code.equals("200")) {
                String certData = StringUtil.getXmlField(result, "Cert");
                System.out.println("certData=====" + certData);
                cert = new X509Cert(certData.getBytes());
                IoUtil.write("./TestData/cert/11111111.cer", cert.getEncoded());
                IoUtil.write("./TestData/cert/11111111.pfx", PKCS12.generatePfx(cert, privateKey, "11111111").getEncoded());

            } else {
                System.out.println(result);
            }

        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }

    public static String getApplyCertStrategyXML() throws Exception {

        StringBuilder applyCertStrategyXML = new StringBuilder("<Request>");

        applyCertStrategyXML.append("<CustomerType>7</CustomerType>");
        applyCertStrategyXML.append("<CertLevel>1</CertLevel>");

        applyCertStrategyXML.append("<KeyAlg>RSA</KeyAlg>");
        applyCertStrategyXML.append("<KeyLength>2048</KeyLength>");

        applyCertStrategyXML.append("<UserName>clientcfca.11114445</UserName>");
        applyCertStrategyXML.append("<IdentificationType>Z</IdentificationType>");
        applyCertStrategyXML.append("<IdentificationNo>cfca111245692223</IdentificationNo>");
        applyCertStrategyXML.append("<SelfExtValue>pdfHash:Ea889djfkdjf</SelfExtValue>");
        applyCertStrategyXML.append("<P10>" + p10String + "</P10>");
        applyCertStrategyXML.append("</Request>");

        return applyCertStrategyXML.toString();
    }

    private static void createP10() throws Exception {
        JCrypto.getInstance().initialize(JCrypto.JSOFT_LIB, null);
        Session session = JCrypto.getInstance().openSession(JCrypto.JSOFT_LIB);

        P10Request p10Request = new P10Request(session);
        Mechanism mechanism = new Mechanism(Mechanism.SHA256_RSA);
        byte[] p10 = p10Request.generatePKCS10Request(mechanism, 2048, session);
        p10String = new String(p10);
        privateKey = p10Request.getPrivateKey();

    }

}
